# asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个EventLoop的引用，然后把需要执行的协程扔到EventLoop中执行，就实现了异步IO。
# 可以实现单线程并发IO操作,。如果仅用在客户端，发挥的威力不大。如果把asyncio用在服务器端，例如Web服务器，由于HTTP连接就是IO操作，因此可以用单线程+coroutine实现多用户的高并发支持。
import asyncio, threading, readline


@asyncio.coroutine  # 把一个generator(yield)标记为coroutine类型，然后，我们就把这个coroutine扔到EventLoop中执行。
def hello():
    print('Hello world! (%s) ' % threading.currentThread())
    # 异步调用asyncio.sleep(1)
    # asyncio.sleep()也是一个coroutine,而是直接中断并执行下一个消息循环。
    # 当asyncio.sleep()返回时，线程就可以从yield from拿到返回值（此处是None）
    yield from asyncio.sleep(1)
    # await asyncio.sleep(1)  # 新版本已经用async,await 关键词代替@asyncio.coroutine,yield
    print('Hello again!(%s) ' % threading.currentThread())


# 获取eventloop
loop = asyncio.get_event_loop()
tasks = [hello(), hello()]
# 执行coroutin
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
# 由打印的当前线程名称可以看出，两个coroutine是由同一个线程并发执行的。
print('*************************************换成IO单线程操作*******************************************')


# asyncio的异步网络连接来获取sina、sohu和163的网站首页
async def webget(host):
    print('wget %s ' % host)
    connect = asyncio.open_connection(host, 80)
    # 这里耗时，暂停，等带下一个进来，需要协程
    reader, writer = await connect
    header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' % host
    writer.write(header.encode('utf-8'))
    # 写入耗时，等待
    print('wget 2222222222222222222222222  %s ' % host)
    await writer.drain()
    while True:
        line = await reader.readline()
        # 判断
        if line == b'\r\n':
            break
    print('%s header > %s' % (host, line.decode('utf-8').rstrip()))
    writer.close()


loop2 = asyncio.new_event_loop()
tasks2 = [webget(host) for host in ['www.sina.com.cn', 'www.sohu.com', 'www.163.com']]
loop2.run_until_complete(asyncio.wait(tasks2))
loop2.close()
# 小结
# asyncio提供了完善的异步IO支持；
#
# 异步操作需要在coroutine中通过yield from完成；
#
# 多个coroutine可以封装成一组Task然后并发执行
